using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.IO;
using System.Threading;
using System.Reflection;
using ViewOn.Kernel;
using ViewOnCore;
using ViewOnCore.Helper.Debug;
using ViewOnCore.Helper.Security;
using ViewOnCore.Device;
using ViewOnCore.Visual;
using ViewOnCore.HostContract;
using ViewOnCore.HostContract.Tasks;

namespace ViewOn.AddInsHostContract
{
    /// <summary>
    /// Concrete implementation of IHostContract
    /// </summary>
    sealed public class ViewOnHostContract : IHostContract
    {

        #region Variables

        //---- Tasks management
        private Queue<Task> _tasksQueue = new Queue<Task>();

        #endregion

        #region Constructor

        internal static void InstallHost()
        {
            Host.Instance = new ViewOnHostContract();
            Host.SettingsService = new ViewOn.AddInsHostContract.Settings.SettingsService();
            Host.SettingsService.CurrentCulture = Host.SettingsService.CurrentCulture;

            Host.MediaService = new ViewOn.AddInsHostContract.Media.MediaService();
            Host.VisualService = new ViewOn.AddInsHostContract.Visual.VisualService();
            Host.UIService = new ViewOn.AddInsHostContract.UI.UIService();
            Host.BurningService = new ViewOn.AddInsHostContract.Burning.BurningService();
            Host.AutoUpdateService = new ViewOn.AddInsHostContract.AutoUpdate.AutoUpdateService();

            Host.UIService.Initialize(System.Windows.Application.Current.Resources);
        }

        #endregion

        #region ApplicationExit

        internal void ApplicationExit()
        {
            //---- Wait until all the tasks are dones !
            while (_tasksQueue.Count > 0)
                Thread.Sleep(100);
        }

        #endregion

        #region Tasks : EnqueueTask/EnqueueUniqueTask

        public void EnqueueTask(Task task)
        {
            try
            {
                Host.NotifyTaskStarted(task);
            }
            catch (Exception e)
            {
                LogManager.Trace(LogType.Warning, "Error occur during Enqueuing task :" + e.Message);
            }

            lock (_tasksQueue)
            {
                Host.TasksCount++;

                _tasksQueue.Enqueue(task);

                if (_tasksQueue.Count < 2)
                    ThreadPool.QueueUserWorkItem(new WaitCallback(_tasksQueue.Peek().InternalExecute));
            }
        }

        public void EnqueueUniqueTask(Task task)
        {
            Type taskType = task.GetType();
            bool hasOtherKindOfTask = false;
            lock (_tasksQueue)
            {
                // Check if all the tasks are "playing tasks"
                foreach (Task currentTask in _tasksQueue)
                    if (currentTask.GetType().Equals(taskType))
                        currentTask.Cancel(); // Cancel previous playing tasks
                    else
                    {
                        hasOtherKindOfTask = true;
                        break;
                    }
            }

            if (!hasOtherKindOfTask)
                EnqueueTask(task);
            else
                ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncExecuteDirectTask), task);
        }

        private void AsyncExecuteDirectTask(object state)
        {
            Task task = state as Task;
            task.Execute();
        }

        #endregion

        #region Tasks : OnTaskCompleted

        /// <summary>
        /// Called when a task is complete.
        /// </summary>
        /// <param name="task">The completed task</param>
        public void OnTaskCompleted(Task completedTask)
        {
            lock (_tasksQueue)
                Host.TasksCount--;

            try
            {
                Host.NotifyTaskCompleted(completedTask);
            }
            catch (Exception e)
            {
                LogManager.Trace(LogType.Warning, "Error occur during Enqueuing task :" + e.Message);
            }

            lock (_tasksQueue)
            {
                _tasksQueue.Dequeue();

                if (_tasksQueue.Count < 1)
                    return;

                ThreadPool.QueueUserWorkItem(new WaitCallback(_tasksQueue.Peek().InternalExecute));
            }
        }

        #endregion

        #region CreateEncrypter

        public XmlEncrypter CreateEncrypter()
        {
            return new XmlEncrypter("123456789viewon987654321");
        }

        #endregion

        #region InsureSerialRegistration

        /// <summary>
        /// This method insure that all the external component natively
        /// used by ViewOn.tv are registered correctly for the current AddIn.
        /// </summary>
        /// <param name="bassNetType">The type of the class "Un4seen.Bass.BassNet" used for Bass.NET registration.</param>
        /// <param name="sharePodLibType">The type of the class "SharePodLib.SharePodLib" used for SharePodLib registration.</param>
        public void InsureSerialRegistration(Type bassNetType, Type sharePodLibType)
        {
            if (bassNetType != null)
            {
                MethodInfo method = bassNetType.GetMethod("Registration");
                method.Invoke(null, new object[] { "viewon01@viewon.tv", "2X1729118172917" });
                //Un4seen.Bass.BassNet.Registration("viewon01@viewon.tv", "2X1729118172917");
            }

            if (sharePodLibType != null)
            {
                MethodInfo method = sharePodLibType.GetMethod("SetLicence");
                method.Invoke(null, new object[] { "ViewOn Media Services", "/uvG3TLvmCa+5RtWc0iRdoYcx9x9bcdEA80e" });
            }
        }

        #endregion

    }
}
